﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using OpenComposite.EII.Repository;
using System.ComponentModel;
using OpenComposite.Base.Collections;
using OpenComposite.Repository.Properties;
using System.Diagnostics;
using System.Threading;
using OpenComposite.EII.Forms;

namespace OpenComposite.EII.Controls
{
	public class RepositoryHierarchyTreeView : TreeView
	{
		#region Constants
		private const string sBusinessObjectFolder = "Business Objects";
		private const string sCapabilitiesFolder = "Capabilities";
		private const string sRulesFolder = "Rules";
		private const string sProcessesFolder = "(internal only) Processes";
		private const string sProcessesMashupFolder = "Mashups";
		private const string sProcessesBPFolder = "Business Processes";
		private const string sProcessesCompositeFolder = "Composites";
		private const string sLogicalMethodsFolder = "Logical Methods";
		private const string sProcessInterface = "Process Interface";
		private const string sHumandActivitiesFolder = "Human Activities";
		private const string sWebServicesFolder = "Web Services";
		private const string sNounsFolder = "Nouns";
		private const string sRuleConstantsFolder = "Rule Constants";

		#endregion

		#region Constructors
		public RepositoryHierarchyTreeView(RepositoryItemBaseEx repositoryItem)
			: this()
		{
			_repItem = repositoryItem;
			load();
		}

		public RepositoryHierarchyTreeView()
			: base()
		{
			init();
		}
		#endregion

		private void init()
		{
			ShowPlusMinus = true;
			ShowRootLines = true;

			this.MouseDown += new MouseEventHandler(UsedByHierarchyTreeView_MouseDown);

			#region ContextMenus

			System.Drawing.Bitmap img = Resources.refresh;

			#region init ContextMenu
			_contextMenu = new ContextMenuStrip();
			_contextMenu.Items.Add("Edit", null, new EventHandler(EditElement));
			_contextMenu.Items.Add("Open", null, new EventHandler(OpenElement));
			_contextMenu.Items.Add(new ToolStripSeparator());
			_contextMenu.Items.Add("Expand Child Elements", Resources.tree_expandall, new EventHandler(ExpandAll));
			_contextMenu.Items.Add("Collapse All", Resources.tree_collapseall, new EventHandler(CollapseAll));
			_contextMenu.Items.Add(new ToolStripSeparator());
			_contextMenu.Items.Add("Refresh", img, new EventHandler(refreshView));
			#endregion

			#region init RefreshMenu
			_refreshMenu = new ContextMenuStrip();
			_refreshMenu.Items.Add("Refresh", img, new EventHandler(refreshView));
			#endregion

			#endregion

			initWorker();

			#region init Debug
			this.KeyUp += new KeyEventHandler(RepositoryHierarchyTreeView_KeyUp);
			#endregion

			ImageList = Helpers.GetRepositoryItemTypeImageList();
		}

		private void initWorker()
		{
			#region init BackgroundWorker
			_worker = new BackgroundWorker();
			_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
			_worker.ProgressChanged += new ProgressChangedEventHandler(_worker_ProgressChanged);
			_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
			_worker.WorkerSupportsCancellation = true;
			_worker.WorkerReportsProgress = true;
			#endregion
		}

		private void load()
		{
			if ( _worker != null && _worker.IsBusy ) {
				_worker.CancelAsync();
				while ( _worker != null && _worker.IsBusy ) { Application.DoEvents(); }
			}

			initWorker();

			_nouns = null;
			_businessObjects = null;
			_logicalMethods = null;
			_processes = null;
			_rules = null;
			_capabilities = null;
			_processesBP = null;
			_processesComposite = null;
			_processesMashup = null;
			_workflowInterface = null;
			_webservices = null;
			_humanActivities = null;
			_ruleConstants = null;
			CheckOrAddAllFolders();

			_rootNode = createTreeNode(_worker, _repItem, false);
			_rootNode.Text += " (loading...)";
			try {
				_worker.RunWorkerAsync();
			} catch ( Exception ex ) {
				Debug.WriteLine(ex);
				_rootNode.Text = RepositoryItem.Name;

				DialogResult result = MessageBox.Show("An error occured while loading the used by hierarchy", "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error);
				if ( result == DialogResult.Retry ) {
					load();
				}
			}
		}

		#region Event Handlers
		#region BackgroundWorker
		void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			_rootNode.Text = RepositoryItem.Name;
			BackgroundWorker worker = sender as BackgroundWorker;
			worker.DoWork -= new DoWorkEventHandler(_worker_DoWork);
			worker.ProgressChanged -= new ProgressChangedEventHandler(_worker_ProgressChanged);
			worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
			worker.Dispose();
			worker = null;
		}

		void _worker_DoWork(object sender, DoWorkEventArgs e)
		{
			BackgroundWorker worker = sender as BackgroundWorker;
			if ( worker != null ) {
				if ( worker.CancellationPending ) {
					e.Cancel = true;
					return;
				}
				if ( e.Argument == null ) {
					worker.ReportProgress(0, new WorkerState(TraverseAction.Invoke, new VoidAction(BeginUpdate)));
					worker.ReportProgress(0, new WorkerState(TraverseAction.Invoke, new VoidAction(Nodes.Clear)));
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRootNode));
					worker.ReportProgress(0, new WorkerState(TraverseAction.Invoke, new VoidAction(EndUpdate)));
					if ( worker.CancellationPending ) {
						e.Cancel = true;
						return;
					}
					getUsingItems(worker, _rootNode);
					while ( !this.IsHandleCreated ) Application.DoEvents();
					if ( InvokeRequired ) {
						worker.ReportProgress(0, new WorkerState(TraverseAction.EnqueueExpand, _rootNode));
					} else {
						_rootNode.Expand();
					}
				} else if ( e.Argument is TreeNodeCollection ) {
					foreach ( TreeNode node in e.Argument as TreeNodeCollection ) {
						if ( worker.CancellationPending ) {
							e.Cancel = true;
							return;
						}
						worker.ReportProgress(0, new WorkerState(TraverseAction.Invoke, new VoidAction(node.Nodes.Clear)));
						getUsingItems(worker, node, true);
					}
				}
			}
		}

		void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			BackgroundWorker worker = sender as BackgroundWorker;
			if ( worker == null ) return;
			WorkerState state = e.UserState as WorkerState;
			if ( state.FolderToAdd == FolderType.Nouns ) throw new InvalidEnumArgumentException("Foldertype.Nouns is not supported by UsedByHieararchy");
			switch ( state.CurrentAction ) {
				#region NotSpecified
				case TraverseAction.NotSpecified:
					return;
				#endregion
				#region EnqueueExpand
				case TraverseAction.EnqueueExpand:
					//if ( !worker.IsBusy ) {
					//    OnBeforeExpand(new TreeViewCancelEventArgs(state.CurrentNode, false, TreeViewAction.Expand));
					//} else {
					state.CurrentNode.Expand();
					//}
					break;
				#endregion
				#region Invoke
				case TraverseAction.Invoke:
					if ( state.MethodToInvoke == null ) return;
					state.MethodToInvoke.Invoke();
					break;
				#endregion
				#region AddRootNode
				case TraverseAction.AddRootNode:
					Nodes.Add(_rootNode);
					break;
				#endregion
				#region Add/AddRange
				case TraverseAction.Add:
				case TraverseAction.AddRange:
					if ( state.CurrentNode == null ) throw new ArgumentNullException("CurrentNode");
					if ( state.NodesToAdd == null ) throw new ArgumentNullException("NodesToAdd");
					if ( state.CurrentNode == _processes ) {
						foreach ( TreeNode tn in state.NodesToAdd ) {
							switch ( ( (Repository.Workflow)tn.Tag ).Type ) {
								case WorkflowType.Orchestration:
									if ( !_processesComposite.Nodes.ContainsKey(tn.Name) )
										_processesComposite.Nodes.Add(tn);
									break;
								case WorkflowType.Business_Process:
									if ( !_processesBP.Nodes.ContainsKey(tn.Name) )
										_processesBP.Nodes.Add(tn);
									break;
								case WorkflowType.Mashup:
								case WorkflowType.Mashup_Horizontal:
									if ( !_processesMashup.Nodes.ContainsKey(tn.Name) )
										_processesMashup.Nodes.Add(tn);
									break;
								default:
									break;
							}
						}
					} else {
						foreach ( TreeNode tn in state.NodesToAdd ) {
							if ( tn == null ) continue;
							if ( !state.CurrentNode.Nodes.ContainsKey(tn.Name) &&
								 !itemExistsRecursive(state.CurrentNode, tn) ) {
								state.CurrentNode.Nodes.Add(tn);
							}
						}
					}
					break;
				#endregion
				default:
					MessageBox.Show("This Action is not implemented!",
						"Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
					break;
			}
			if ( state.CurrentAction == TraverseAction.Add || state.CurrentAction == TraverseAction.AddRange ) {
				CheckOrAddAllFolders();
			}
		}

		#endregion

		#region ContextMenu
		void OpenElement(object sender, EventArgs e)
		{
			IMainController mc = _repItem.GetService(typeof(IMainController)) as IMainController;
			if ( mc != null ) {
				TreeNode node = this.SelectedNode;
				RepositoryItemBase item = node.Tag as RepositoryItemBase;
				if ( item != null ) {
					RepositoryBusinessRule rule = item as RepositoryBusinessRule;
					if ( rule != null ) {
						BusinessPolicy policy = rule.GetPolicy();
						mc.OpenDiagram(policy);
					} else {
						mc.OpenDiagram(item);
					}
				}
			}
		}
		void EditElement(object sender, EventArgs e)
		{
			if ( this.SelectedNode != null && this.SelectedNode.Tag is IRepositoryItem ) {
				( (IRepositoryItem)this.SelectedNode.Tag ).ShowDetails();
			}
		}

		void ExpandAll(object sender, EventArgs e)
		{
			this.BeginUpdate();
			SelectedNode.Expand();
			this.EndUpdate();
			this.BeginUpdate();
			foreach ( TreeNode node in SelectedNode.Nodes ) {
				node.Expand();
			}
			this.EndUpdate();
			//SelectedNode.ExpandAll();
		}

		void CollapseAll(object sender, EventArgs e)
		{
			this.BeginUpdate();
			SelectedNode.Collapse(false);
			this.EndUpdate();
		}

		void refreshView(object sender, EventArgs e)
		{
			load();
		}

		void UsedByHierarchyTreeView_MouseDown(object sender, MouseEventArgs e)
		{
			if ( e.Button == MouseButtons.Right ) {
				SelectedNode = GetNodeAt(e.Location);
				if ( SelectedNode != null ) {
					RepositoryItemBase item = SelectedNode.Tag as RepositoryItemBase;
					_contextMenu.Items[0].Enabled = true;
					_contextMenu.Items[1].Enabled = true;
					_contextMenu.Items[3].Enabled = true;
					_contextMenu.Items[4].Enabled = true;
					if ( item != null ) {
						switch ( item.RepositoryItemType ) {
							case ItemType.LogicalWebMethod:
							case ItemType.Noun:
							case ItemType.GenericFolder:
							case ItemType.Verb:
							case ItemType.WebMethod:
							case ItemType.WebService:
							case ItemType.Workflow_Method:
							case ItemType.Workflow_Field:
							case ItemType.Workflow_Event:
								_contextMenu.Items[1].Enabled = false;
								break;
							default:
								break;
						}
					} else {
						_contextMenu.Items[1].Enabled = false;
					}
					if ( SelectedNode.Tag == null ) {
						_contextMenu.Items[0].Enabled = false;
					}
				} else {
					_refreshMenu.Show(this, e.Location);
				}
			}
		}

		#endregion

		void RepositoryHierarchyTreeView_KeyUp(object sender, KeyEventArgs e)
		{
			if ( e.Control && e.Alt && e.KeyCode == Keys.I ) {
				RepositoryItemBase item = SelectedNode.Tag as RepositoryItemBase;
				Helpers.OpenDebugViewer(item, this);
			}
		}
		#endregion

		#region getItemsOfRepositoryItem
		///  Schema
		/// getItemsOfType(Type item, bool deeper){
		///	get SearchableSortableBindingList of items using parameter item
		///	--- or ---
		///	get items of the parameter items properties
		///	add the items to the return value (using createTreeNode() / createTreeNodeArray())
		/// }

		protected virtual TreeNode[] getItemsOfNoun(BackgroundWorker worker, Noun item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfBusinessObject(BackgroundWorker worker, BusinessObject item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfVerb(BackgroundWorker worker, Verb item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfBusinessRule(BackgroundWorker worker, RepositoryBusinessRule item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfLogicalMethod(BackgroundWorker worker, LogicalWebMethod item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfWebMethod(BackgroundWorker worker, WebMethod item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfWebService(BackgroundWorker worker, WebService item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfHumanActivity(BackgroundWorker worker, Repository.HumanActivity item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfRuleConstants(BackgroundWorker worker, RuleConstant item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfCapability(BackgroundWorker worker, ServiceModule item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		protected virtual TreeNode[] getItemsOfWorkflow(BackgroundWorker worker, Repository.Workflow item, bool deeper)
		{
			List<TreeNode> nodes = new List<TreeNode>();

			return nodes.ToArray();
		}
		#endregion

		#region [Async] getItemsOfRepositoryItem
		// Schema
		// getItemsOfTypeAsync(Type item){
		//	--- do this for each Type using the parameter item ---
		//	CheckOrAddFolder(FolderType)
		//	create SearchableSortableBindingList of Items using parameter item
		//	--- or ---
		//	get items of the parameter items properties
		//	report progress to worker, 
		//		use Action.Add or Action.AddRange, 
		//		use the correct folder node (see enum FolderType for further information), 
		//		use createTreeNode() / createTreeNodeArray() on the SearchableSortableBindingList
		//	--- optionally get items using using items (e.g. get items using BusinessObjects which are using a Noun) ---
		//	--- !!!use this with caution of endless loops!!! ---
		//	use getItemsOfTypeAsync() for each item in the SearchableSortableBindingList
		// }

		protected virtual void getItemsOfNounAsync(BackgroundWorker worker, Noun item)
		{
			if ( _worker.CancellationPending ) return;
		}

		protected virtual void getItemsOfBusinessObjectAsync(BackgroundWorker worker, BusinessObject item)
		{
			if ( _worker.CancellationPending ) return;
		}

		protected virtual void getItemsOfVerbAsync(BackgroundWorker worker, Verb item)
		{
			if ( _worker.CancellationPending ) return;
		}

		protected virtual void getItemsOfBusinessRuleAsync(BackgroundWorker worker, RepositoryBusinessRule item)
		{
			if ( _worker.CancellationPending ) return;
		}

		protected virtual void getItemsOfLogicalMethodAsync(BackgroundWorker worker, LogicalWebMethod item)
		{
			if ( _worker.CancellationPending ) return;
		}

		protected virtual void getItemsOfWebMethodAsync(BackgroundWorker worker, WebMethod item)
		{
			if ( _worker.CancellationPending ) return;
		}

		protected virtual void getItemsOfWebServiceAsync(BackgroundWorker worker, WebService item)
		{
			if ( _worker.CancellationPending ) return;
		}

		protected virtual void getItemsOfHumanActivityAsync(BackgroundWorker worker, Repository.HumanActivity item)
		{
		}

		protected virtual void getItemsOfRuleConstantsAsync(BackgroundWorker worker, RuleConstant item)
		{
		}

		protected virtual void getItemsOfCapabilityAsync(BackgroundWorker worker, ServiceModule item)
		{
		}

		protected virtual void getItemsOfWorkflowAsync(BackgroundWorker worker, Repository.Workflow item)
		{
		}
		#endregion

		/// <summary>
		/// Starts action asynchronous
		/// </summary>
		/// <param name="node"></param>
		protected void getUsingItems(BackgroundWorker worker, TreeNode node)
		{
			RepositoryItemBase item = node.Tag as RepositoryItemBase;
			if ( item == null ) throw new NullReferenceException("RepositoryItem is not set to an instance of an object.");
			#region switch ( itemType)
			switch ( item.RepositoryItemType ) {
				case ItemType.Undefined:
					break;
				case ItemType.Domain:
					break;
				case ItemType.Noun:
					getItemsOfNounAsync(worker, item as Noun);
					break;
				case ItemType.Component:
					break;
				case ItemType.Operation:
					break;
				case ItemType.BRule:
					getItemsOfBusinessRuleAsync(worker, item as RepositoryBusinessRule);
					break;
				case ItemType.BObject:
					getItemsOfBusinessObjectAsync(worker, item as BusinessObject);
					break;
				case ItemType.Capability:
					break;
				case ItemType.ExposedCapability:
					break;
				case ItemType.Verb:
					getItemsOfVerbAsync(worker, item as Verb);
					break;
				case ItemType.LogicalMethodGroup:
					break;
				case ItemType.LogicalWebMethod:
					getItemsOfLogicalMethodAsync(worker, item as LogicalWebMethod);
					break;
				case ItemType.Repository:
					break;
				case ItemType.GenericFolder:
					break;
				case ItemType.BPolicy:
					break;
				case ItemType.Container:
					break;
				case ItemType.Route:
					break;
				case ItemType.Label:
					break;
				case ItemType.Separator:
					break;
				case ItemType.And:
					break;
				case ItemType.Or:
					break;
				case ItemType.XOr:
					break;
				case ItemType.While:
					break;
				case ItemType.Activity:
					break;
				case ItemType.Organization:
					break;
				case ItemType.OrgUnit:
					break;
				case ItemType.Group:
					break;
				case ItemType.Role:
					break;
				case ItemType.User:
					break;
				case ItemType.BRule_If:
					break;
				case ItemType.BRule_ThenElse:
					break;
				case ItemType.BRule_And:
					break;
				case ItemType.BRule_Or:
					break;
				case ItemType.RuleConstant:
					getItemsOfRuleConstantsAsync(worker, item as RuleConstant);
					break;
				case ItemType.SCA_Export:
					break;
				case ItemType.SCA_Import:
					break;
				case ItemType.SCA_StandaloneReference:
					break;
				case ItemType.Composite:
					getItemsOfCapabilityAsync(worker, item as ServiceModule);
					break;
				case ItemType.CompositeReference:
					break;
				case ItemType.SCA_External:
					break;
				case ItemType.OrchestrationComponent:
					break;
				case ItemType.RuleComponent:
					break;
				case ItemType.HumanComponent:
					break;
				case ItemType.SQLComponent:
					break;
				case ItemType.UIComponent:
					break;
				case ItemType.Diagram:
					break;
				case ItemType.Business_SCA:
					break;
				case ItemType.SOBA:
					break;
				case ItemType.SOA:
					break;
				case ItemType.FA_View:
					break;
				case ItemType.FA_Domain:
					break;
				case ItemType.FA_Service:
					break;
				case ItemType.ITObject:
					break;
				case ItemType.BObjectIcon:
					break;
				case ItemType.Selector:
					break;
				case ItemType.System:
					break;
				case ItemType.Mapping:
					break;
				case ItemType.Business_Process:
					break;
				case ItemType.BProcess_Start:
					break;
				case ItemType.BProcess_End:
					break;
				case ItemType.Workflow:
					getItemsOfWorkflowAsync(worker, item as Repository.Workflow);
					break;
				case ItemType.LogicalActivity:
					break;
				case ItemType.Workflow_Method:
					break;
				case ItemType.Workflow_Event:
					break;
				case ItemType.Workflow_Field:
					break;
				case ItemType.WebService:
					getItemsOfWebServiceAsync(worker, item as WebService);
					break;
				case ItemType.APIService:
					break;
				case ItemType.WebMethod:
					getItemsOfWebMethodAsync(worker, item as WebMethod);
					break;
				case ItemType.KPI:
					break;
				case ItemType.KPI_Metric:
					break;
				case ItemType.KPI_Function:
					break;
				case ItemType.KPI_Schedule:
					break;
				case ItemType.BUS:
					break;
				case ItemType.BUSActivity:
					break;
				case ItemType.BUSDocument:
					break;
				case ItemType.BUSPublish:
					break;
				case ItemType.BUSSubscribe:
					break;
				case ItemType.BUSVariables:
					break;
				case ItemType.HumanActivity:
					getItemsOfHumanActivityAsync(worker, item as Repository.HumanActivity);
					break;
				case ItemType.Mashup:
					break;
				default:
					break;
			}
			#endregion
			//getUsingItems(node, true);
		}

		/// <summary>
		/// Starts action non-asynchronous (when expanding a TreeNode)
		/// </summary>
		/// <param name="node"></param>
		/// <param name="deeper"></param>
		protected void getUsingItems(BackgroundWorker worker, TreeNode node, bool deeper)
		{
			RepositoryItemBase item = node.Tag as RepositoryItemBase;
			if ( item == null ) throw new NullReferenceException("RepositoryItem is not set to an instance of an object.");
			#region switch
			switch ( item.RepositoryItemType ) {
				case ItemType.Undefined:
					break;
				case ItemType.Domain:
					break;
				case ItemType.Noun:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfNoun(worker, item as Noun, deeper)));
					break;
				case ItemType.Component:
					break;
				case ItemType.Operation:
					break;
				case ItemType.BRule:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfBusinessRule(worker, item as RepositoryBusinessRule, deeper)));
					break;
				case ItemType.BObject:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfBusinessObject(worker, item as BusinessObject, deeper)));
					break;
				case ItemType.Capability:
					break;
				case ItemType.ExposedCapability:
					break;
				case ItemType.Verb:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfVerb(worker, item as Verb, deeper)));
					break;
				case ItemType.LogicalMethodGroup:
					break;
				case ItemType.LogicalWebMethod:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfLogicalMethod(worker, item as LogicalWebMethod, deeper)));
					break;
				case ItemType.Repository:
					break;
				case ItemType.GenericFolder:
					break;
				case ItemType.BPolicy:
					break;
				case ItemType.Container:
					break;
				case ItemType.Route:
					break;
				case ItemType.Label:
					break;
				case ItemType.Separator:
					break;
				case ItemType.And:
					break;
				case ItemType.Or:
					break;
				case ItemType.XOr:
					break;
				case ItemType.While:
					break;
				case ItemType.Activity:
					break;
				case ItemType.Organization:
					break;
				case ItemType.OrgUnit:
					break;
				case ItemType.Group:
					break;
				case ItemType.Role:
					break;
				case ItemType.User:
					break;
				case ItemType.BRule_If:
					break;
				case ItemType.BRule_ThenElse:
					break;
				case ItemType.BRule_And:
					break;
				case ItemType.BRule_Or:
					break;
				case ItemType.RuleConstant:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfRuleConstants(worker, item as RuleConstant, deeper)));
					break;
				case ItemType.SCA_Export:
					break;
				case ItemType.SCA_Import:
					break;
				case ItemType.SCA_StandaloneReference:
					break;
				case ItemType.Composite:
				case ItemType.CompositeReference:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfCapability(worker, item as ServiceModule, deeper)));
					break;
				case ItemType.SCA_External:
					break;
				case ItemType.OrchestrationComponent:
					break;
				case ItemType.RuleComponent:
					break;
				case ItemType.HumanComponent:
					break;
				case ItemType.SQLComponent:
					break;
				case ItemType.UIComponent:
					break;
				case ItemType.Diagram:
					break;
				case ItemType.Business_SCA:
					break;
				case ItemType.SOBA:
					break;
				case ItemType.SOA:
					break;
				case ItemType.FA_View:
					break;
				case ItemType.FA_Domain:
					break;
				case ItemType.FA_Service:
					break;
				case ItemType.ITObject:
					break;
				case ItemType.BObjectIcon:
					break;
				case ItemType.Selector:
					break;
				case ItemType.System:
					break;
				case ItemType.Mapping:
					break;
				case ItemType.Business_Process:
					break;
				case ItemType.BProcess_Start:
					break;
				case ItemType.BProcess_End:
					break;
				case ItemType.Mashup:
				case ItemType.Workflow:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfWorkflow(worker, item as Repository.Workflow, deeper)));
					break;
				case ItemType.LogicalActivity:
					break;
				case ItemType.Workflow_Method:
					worker.ReportProgress(0, new WorkerState(TraverseAction.Add, node,
						createTreeNode(worker, ( item as WorkflowMethod ).Workflow, false)));
					break;
				case ItemType.Workflow_Event:
					worker.ReportProgress(0, new WorkerState(TraverseAction.Add, node,
						createTreeNode(worker, ( item as WorkflowEvent ).Workflow, false)));
					break;
				case ItemType.Workflow_Field:
					worker.ReportProgress(0, new WorkerState(TraverseAction.Add, node,
						createTreeNode(worker, ( item as WorkflowField ).Workflow, false)));
					break;
				case ItemType.WebService:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfWebService(worker, item as WebService, deeper)));
					break;
				case ItemType.APIService:
					break;
				case ItemType.WebMethod:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfWebMethod(worker, item as WebMethod, deeper)));
					break;
				case ItemType.KPI:
					break;
				case ItemType.KPI_Metric:
					break;
				case ItemType.KPI_Function:
					break;
				case ItemType.KPI_Schedule:
					break;
				case ItemType.BUS:
					break;
				case ItemType.BUSActivity:
					break;
				case ItemType.BUSDocument:
					break;
				case ItemType.BUSPublish:
					break;
				case ItemType.BUSSubscribe:
					break;
				case ItemType.BUSVariables:
					break;
				case ItemType.HumanActivity:
					worker.ReportProgress(0, new WorkerState(TraverseAction.AddRange, node,
						getItemsOfHumanActivity(worker, item as Repository.HumanActivity, deeper)));
					break;
				default:
					break;
			}
			#endregion
		}

		#region TreeNode creators
		/// <summary>
		/// Creates an Array of TreeNodes based on a SearchableSortableBindingList of RepositoryItemBase
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="items"></param>
		/// <param name="deeper"></param>
		/// <returns></returns>
		protected virtual TreeNode[] createTreeNodeArray<T>(BackgroundWorker worker, BindingListEx<T> items, bool deeper) where T : RepositoryItemBase
		{
			List<TreeNode> list = new List<TreeNode>();
			foreach ( RepositoryItemBase item in items ) {
				if ( items != null ) { // workflow interface
					TreeNode node = createTreeNode(worker, item, deeper);
					list.Add(node);
				}
			}
			return list.ToArray();
		}

		/// <summary>
		/// Creates a TreeNode based on a RepositoryItemBase
		/// </summary>
		/// <param name="item"></param>
		/// <param name="deeper"></param>
		/// <returns></returns>
		protected TreeNode createTreeNode(BackgroundWorker worker, RepositoryItemBase item, bool deeper)
		{
			RepositoryItemBaseEx ex = item as RepositoryItemBaseEx;
			if ( ex != null ) {
				if ( ex.IsDeleted ) {
					return null;
				}
			}
			string name = string.Format("{0}.{1}", item.Name, item.ID);
			string text;
			if ( item is RepositoryBusinessRule ) {
				text = string.Format("{0} ({1})", item.Name, item.NText);
			} else {
				text = item.Name;
			}
			TreeNode tn = new TreeNode(text);
			tn.Name = name;
			tn.Tag = item;
			tn.SelectedImageKey = item.ImageKey;
			tn.StateImageKey = item.ImageKey;
			tn.ImageKey = item.ImageKey;
			tn.ContextMenuStrip = _contextMenu;
			if ( deeper ) getUsingItems(worker, tn, false);
			//if ( item is BusinessObject && !_bobjList.Contains(item.ID) ) {
			//    _bobjList.Add(item.ID);
			//}

			return tn;
		}

		/// <summary>
		/// Create a folder with specified name ang image key
		/// </summary>
		/// <param name="name"></param>
		/// <param name="imageKey"></param>
		/// <returns></returns>
		private TreeNode createFolderTreeNode(string name, string imageKey)
		{
			TreeNode tn = new TreeNode(name);
			tn.Name = name;
			tn.ImageKey = imageKey;
			tn.SelectedImageKey = imageKey;
			tn.ContextMenuStrip = _contextMenu;
			return tn;
		}
		#endregion

		private bool itemExistsRecursive(TreeNode parent, TreeNode nodeToCheck)
		{
			bool flag = parent.Nodes.ContainsKey(nodeToCheck.Name);
			if ( flag ) return true;

			if ( parent.Parent != null ) {
				flag = itemExistsRecursive(parent.Parent, nodeToCheck);
			}
			return flag;
		}

		protected void CheckOrAddAllFolders()
		{
			CheckOrAddFolder(FolderType.Nouns);
			CheckOrAddFolder(FolderType.BusinessObjects);
			CheckOrAddFolder(FolderType.Capabilities);
			CheckOrAddFolder(FolderType.LogicalMethods);
			CheckOrAddFolder(FolderType.Processes);
			CheckOrAddFolder(FolderType.Rules);
			CheckOrAddFolder(FolderType.WorkflowInterface);
			CheckOrAddFolder(FolderType.RuleConstants);
			CheckOrAddFolder(FolderType.WebServices);
			CheckOrAddFolder(FolderType.HumanActivities);
		}

		private void CheckOrAddFolder(FolderType type)
		{
			switch ( type ) {
				case FolderType.Capabilities:
					#region Capabilities
					if ( _capabilities == null ) {
						_capabilities = createFolderTreeNode(sCapabilitiesFolder,
							"folder_closed_method");
					} else {
						if ( _capabilities.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_capabilities) ) {
							_rootNode.Nodes.Add(_capabilities);
						}
					}
					break;
					#endregion
				case FolderType.Processes:
					#region Processes
					if ( _processes == null ) {
						_processes = new TreeNode(sProcessesFolder);
						_processesBP = createFolderTreeNode(sProcessesBPFolder,
							"folder_closed_bprocess");
						_processesComposite = createFolderTreeNode(sProcessesCompositeFolder,
							"folder_closed_workflows");
						_processesMashup = createFolderTreeNode(sProcessesMashupFolder,
							"folder_closed_mashup");
					} else {
						if ( _processesBP.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_processesBP) ) {
							_rootNode.Nodes.Add(_processesBP);
						}
						if ( _processesComposite.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_processesComposite) ) {
							_rootNode.Nodes.Add(_processesComposite);
						}
						if ( _processesMashup.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_processesMashup) ) {
							_rootNode.Nodes.Add(_processesMashup);
						}
					}
					break;
					#endregion
				case FolderType.BusinessObjects:
					#region Business Objects
					if ( _businessObjects == null ) {
						_businessObjects = createFolderTreeNode(sBusinessObjectFolder,
							"bobj_folder_closed");
					} else {
						if ( _businessObjects.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_businessObjects) ) {
							_rootNode.Nodes.Add(_businessObjects);
						}
					}
					break;
					#endregion
				case FolderType.Rules:
					#region Rules
					if ( _rules == null ) {
						_rules = createFolderTreeNode(sRulesFolder,
							"policy_folder_closed");
					} else {
						if ( _rules.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_rules) ) {
							_rootNode.Nodes.Add(_rules);
						}
					}
					break;
					#endregion
				case FolderType.LogicalMethods:
					#region Logical Web Methods
					if ( _logicalMethods == null ) {
						_logicalMethods = createFolderTreeNode(sLogicalMethodsFolder,
							"folder_closed_logmethod");
					} else {
						if ( _logicalMethods.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_logicalMethods) ) {
							_rootNode.Nodes.Add(_logicalMethods);
						}
					}
					break;
					#endregion
				case FolderType.WorkflowInterface:
					#region Workflow Interface
					if ( _workflowInterface == null ) {
						_workflowInterface = createFolderTreeNode(sProcessInterface,
							"module_folder_closed");
					} else {
						if ( _workflowInterface.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_workflowInterface) ) {
							_rootNode.Nodes.Add(_workflowInterface);
						}
					}
					break;
					#endregion
				case FolderType.HumanActivities:
					#region Human Activities
					if ( _humanActivities == null ) {
						_humanActivities = createFolderTreeNode(sHumandActivitiesFolder,
							"module_folder_closed");
					} else {
						if ( _humanActivities.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_humanActivities) ) {
							_rootNode.Nodes.Add(_humanActivities);
						}
					}
					break;
					#endregion
				case FolderType.WebServices:
					#region Web Services
					if ( _webservices == null ) {
						_webservices = createFolderTreeNode(sWebServicesFolder,
							"folder_closed_webservices");
					} else {
						if ( _webservices.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_webservices) ) {
							_rootNode.Nodes.Add(_webservices);
						}
					}
					break;
					#endregion
				case FolderType.Nouns:
					#region Nouns
					if ( _nouns == null ) {
						_nouns = createFolderTreeNode(sNounsFolder,
							"vocab_folder_closed");
					} else {
						if ( _nouns.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_nouns) ) {
							_rootNode.Nodes.Add(_nouns);
						}
					}
					break;
					#endregion
				case FolderType.RuleConstants:
					#region Rule Constants
					if ( _ruleConstants == null ) {
						_ruleConstants = createFolderTreeNode(sRuleConstantsFolder,
							"folder_closed_constant");
					} else {
						if ( _ruleConstants.Nodes.Count > 0 && !_rootNode.Nodes.Contains(_ruleConstants) ) {
							_rootNode.Nodes.Add(_ruleConstants);
						}
					}
					#endregion
					break;
				default:
					break;
			}
		}

		#region Protected Methods
		protected override void OnBeforeExpand(TreeViewCancelEventArgs e)
		{
			base.OnBeforeExpand(e);
			if ( e.Node != _rootNode && e.Node.Tag != null ) {
				initWorker();
				_worker.RunWorkerAsync(e.Node.Nodes);
			}
		}
		#endregion

		public RepositoryItemBaseEx RepositoryItem
		{
			get { return _repItem; }
			set
			{
				_repItem = value;
				if ( _repItem != null ) load();
			}
		}

		#region Private Fields
		private BackgroundWorker _worker;
		private RepositoryItemBaseEx _repItem = null;
		private ContextMenuStrip _contextMenu = null;
		private ContextMenuStrip _refreshMenu = null;
		#endregion

		#region Protected Fields
		protected volatile TreeNode _rootNode = null;

		#region Folders
		protected volatile TreeNode _capabilities = null;
		protected volatile TreeNode _processes = null;
		protected volatile TreeNode _processesBP = null;
		protected volatile TreeNode _processesMashup = null;
		protected volatile TreeNode _processesComposite = null;
		protected volatile TreeNode _businessObjects = null;
		protected volatile TreeNode _rules = null;
		protected volatile TreeNode _logicalMethods = null;
		protected volatile TreeNode _workflowInterface = null;
		protected volatile TreeNode _webservices = null;
		protected volatile TreeNode _humanActivities = null;
		protected volatile TreeNode _nouns = null;
		protected volatile TreeNode _ruleConstants = null;
		#endregion
		#endregion

		#region Protected Properties
		#endregion
	}

	public delegate void VoidAction();

	#region Class WorkerState
	internal class WorkerState
	{
		/// <summary>
		/// Performs an action without addition data 
		/// Used to
		///		Add root TreeNode
		/// </summary>
		/// <param name="action"></param>
		public WorkerState(TraverseAction action)
		{
			if ( action == TraverseAction.AddRange ) throw new InvalidOperationException("Action.AddRange needs more parameters");
			_currentAction = action;
		}

		/// <summary>
		/// Used to
		///		nothing
		/// </summary>
		/// <param name="action"></param>
		/// <param name="folderType"></param>
		public WorkerState(TraverseAction action, FolderType folderType)
		{
			if ( action == TraverseAction.AddRange ) throw new InvalidOperationException("Action.AddRange needs more parameters");
			_currentAction = action;
			_folderType = folderType;
		}

		/// <summary>
		/// Performs an action on a single node
		/// Used to
		///		Enqueue expand action on a single node
		/// </summary>
		/// <param name="action"></param>
		/// <param name="node"></param>
		public WorkerState(TraverseAction action, TreeNode node)
		{
			if ( action == TraverseAction.AddRange ) throw new InvalidOperationException("Action.AddRange needs more parameters");
			_currentAction = action;
			_currentNode = node;
		}

		/// <summary>
		/// Used to
		///		nothing
		/// </summary>
		/// <param name="action"></param>
		/// <param name="node"></param>
		/// <param name="folderType"></param>
		public WorkerState(TraverseAction action, TreeNode node, FolderType folderType)
		{
			if ( action == TraverseAction.AddRange ) throw new InvalidOperationException("Action.AddRange needs more parameters");
			_currentAction = action;
			_currentNode = node;
			_folderType = folderType;
		}

		/// <summary>
		/// Used to
		///		Add a single TreeNode to a folder TreeNode
		///		Add a workflow interface item to a TreeNode
		/// </summary>
		/// <param name="action"></param>
		/// <param name="targetNode"></param>
		/// <param name="nodeToAdd"></param>
		public WorkerState(TraverseAction action, TreeNode targetNode, TreeNode nodeToAdd)
		{
			if ( action != TraverseAction.Add ) throw new InvalidOperationException("This constructor can only be used for Action.Add");
			if ( targetNode == null ) throw new ArgumentNullException("targetNode");
			if ( nodeToAdd == null ) throw new ArgumentNullException("nodeToAdd");
			_currentAction = action;
			_currentNode = targetNode;
			_nodesToAdd = new TreeNode[] { nodeToAdd };
		}

		/// <summary>
		/// Used to
		///		Add items to a folder TreeNode (by getItemsOfType() methods)
		///		Add items to a node (by getItemsOf() method called by e.g. expanding an item)
		/// </summary>
		/// <param name="action"></param>
		/// <param name="targetNode"></param>
		/// <param name="nodesToAdd"></param>
		public WorkerState(TraverseAction action, TreeNode targetNode, TreeNode[] nodesToAdd)
		{
			if ( targetNode == null ) throw new ArgumentNullException("targetNode");
			_currentAction = action;
			_currentNode = targetNode;
			_nodesToAdd = nodesToAdd;
		}

		public WorkerState(TraverseAction action, VoidAction method)
		{
			if ( action != TraverseAction.Invoke ) throw new InvalidOperationException("A method parameter needs Action.Invoke to work");
			_currentAction = action;
			_method = method;
		}
		private TraverseAction _currentAction = TraverseAction.NotSpecified;
		private TreeNode _currentNode;
		private TreeNode[] _nodesToAdd;
		private FolderType _folderType;
		private VoidAction _method;

		public TraverseAction CurrentAction
		{
			get { return _currentAction; }
		}

		public TreeNode CurrentNode
		{
			get { return _currentNode; }
		}

		public TreeNode[] NodesToAdd
		{
			get { return _nodesToAdd; }
		}

		public FolderType FolderToAdd
		{
			get { return _folderType; }
		}

		public VoidAction MethodToInvoke
		{
			get { return _method; }
		}

	}
	#endregion

	internal enum TraverseAction
	{
		NotSpecified,
		Add,
		AddRootNode,
		AddRange,
		EnqueueExpand,
		Invoke
	}

	#region enum FolderType
	public enum FolderType
	{
		/// <summary>
		/// _capabilities
		/// </summary>
		Capabilities,
		/// <summary>
		/// _processes (is splitted into subfolders by BackgroundWorker)
		/// </summary>
		Processes,
		/// <summary>
		/// _businessObjects
		/// </summary>
		BusinessObjects,
		/// <summary>
		/// _rules
		/// </summary>
		Rules,
		/// <summary>
		/// _logicalMethods
		/// </summary>
		LogicalMethods,
		/// <summary>
		/// _workflowInterface
		/// </summary>
		WorkflowInterface,
		/// <summary>
		/// _webservices
		/// </summary>
		WebServices,
		/// <summary>
		/// _humanActivities
		/// </summary>
		HumanActivities,
		/// <summary>
		/// _nouns (not in UsedByHierarchy)
		/// </summary>
		Nouns,
		/// <summary>
		/// _ruleConstants
		/// </summary>
		RuleConstants
	}
	#endregion
}
